//
//  YsCloudFileDownloadManager.m
//  YsCloudFileManageSDK
//
//  Created by 宋宏康 on 2020/2/27.
//

#import "YsCloudFileDownloadManager.h"
#import "YsCloudFileDownloadManager+Tools.h"
#import "YsCloudFolderManager.h"
#import "YsCloudFileRealmManager.h"
#import "YsCloudFileManageSDKRealm.h"
#import "YsFileUtil.h"
#import "YsCloudRealmTool.h"
#import "YsCloudFileDownloadTools.h"
#import "NSString+YscCloudFileTools.h"
#import "NSArray+QMUI.h"
#import <YYKit/YYKit.h>


@implementation YsCloudFileDownloadManager

static YsCloudFileDownloadManager *_downloadManager = nil;

+ (instancetype)shareDownloadManger
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _downloadManager = [[self alloc] init];
    });
    return _downloadManager;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        /// 设置最大并发数为3
    }
    return self;
}

- (void)downloadWithUrl:(NSString *)downloadUrl
             withPara:(NSString *)para
              withMethod:(NSString *)requestMethod
     withCustomCacheName:(NSString *)customCacheName
  withLastPathComponent:(NSString *)lastPathComponent
{
    SemaphoreBegin;
    /// 加锁
    NSParameterAssert(downloadUrl);
    NSParameterAssert(requestMethod);
    NSParameterAssert(customCacheName);
    YsCloudFileDownloadModel *downloadModel = [[YsCloudFileDownloadModel alloc] initWithProductDownloadModel:YES];
    NSPredicate *query = [NSPredicate predicateWithFormat:@"accountCode == %@",kAccountCode];
    YsCloudFileManageSDKRealm *sdkRealm = (YsCloudFileManageSDKRealm*) [YsCloudFileRealmManager queryObjsWithPredicate:query targetClass:YsCloudFileManageSDKRealm.class].lastObject;
    [YsCloudFileRealmManager updateObj:^{
       [sdkRealm.downloadReamModelArray addObject:downloadModel.downloadReamModel];
    }];
    downloadModel.createTime = NSString.currentTimeStr;
    downloadModel.requestUrl = downloadUrl;
    downloadModel.downloadStatus = 2;
    downloadModel.progress = 0;
    downloadModel.accountCode = kAccountCode;
    downloadModel.waitTaskTime = NSString.currentMillisecondTime;
    downloadModel.lastPathComponent = lastPathComponent;
    downloadModel.customCacheName = [YsCloudFileDownloadTools renameWithRequestUrl:downloadUrl withName:customCacheName];
    downloadModel.requestMethod = requestMethod;
    downloadModel.paramDic = [para copy];
//    downloadModel.tmpPath = [YsCloudFolderManager getTmpDownloadPathTocacheFileWithAccountCode:kAccountCode withDownloadUrl:downloadUrl];
    downloadModel.tmpPath = [YsCloudFolderManager getTmpDownloadPathTocacheFileWithAccountCode:kAccountCode withName:downloadModel.customCacheName];
    [self.downloadsArray addObject:downloadModel];
    
   /// 当前模型的缓存文件是否存在。
//   if (![YsCloudFolderManager checkDownloadFileExistenceWithDownloadModel:downloadModel withAccountCode:kAccountCode]) ;
    /// 开始下载任务
    [self checkDownload];
//    [self beginDownloadWithModel:downloadModel];
    
    SemaphoreEnd;
}

- (void)beginDownloadWithModel:(YsCloudFileDownloadModel *)model {
//    @weakify(self);
    model.downloadStatus = 3;
    //  如果任务正在进行 取消
    [self cancelTask:model];
    //  取消请求的缓存
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    //  开始下载任务
//    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    __block  NSURLSessionConfiguration *config = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:NSString.backgroundSessionIdentifier];
    });

    AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config];
    /// 设置请求超时
    // 设置超时时间 设置一个比较大的值，目的就是为了不超时
    [manager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
    manager.requestSerializer.timeoutInterval = 3600.f;
    [manager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
    
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    NSMutableURLRequest *request = [manager.requestSerializer requestWithMethod:model.requestMethod URLString:model.requestUrl parameters:model.paramDic error:nil];
    // 读取数据
    unsigned long long cacheNumber =  [YsFileUtil readDataWithfilePath:model.tmpPath].length;
    // 断点续传
    if (cacheNumber > 0) {
        NSString *rangStr = [NSString stringWithFormat:@"bytes=%llu-",cacheNumber];
        [request setValue:rangStr forHTTPHeaderField:@"Range"];
    }
    
    [manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) {
        SemaphoreBegin;
        model.downloadStatus = 3;
        // 写入数据
        if (!model.itemFileHandle) {
            model.itemFileHandle = [NSFileHandle fileHandleForWritingAtPath:model.tmpPath];
        }
        [model.itemFileHandle seekToEndOfFile];
        [model.itemFileHandle writeData:data];
        // 计算进度
        unsigned long long receiveNumber = (unsigned long long )dataTask.countOfBytesReceived + cacheNumber;
        unsigned long long expectNumber = (unsigned long long)dataTask.countOfBytesExpectedToReceive + cacheNumber;
        dispatch_async(dispatch_get_main_queue(), ^{
            model.totalSize = expectNumber;
        });
        CGFloat progress = (CGFloat)receiveNumber/expectNumber *1.0;
        
        dispatch_async(dispatch_get_main_queue(), ^{
            model.progress = progress;
        });
        
        NSLog(@"接收的数据 --- %llu 期望的数据 ---- %llu 下载的进度 --- %f",receiveNumber,expectNumber,progress);
        if (model.downloadProgressBlock) {
            model.downloadProgressBlock(progress);
        }
        
        SemaphoreEnd;
    }];
    
//    __weak __typeof__(self) weakSelf = self;
//          UIApplication *application = [UIApplication sharedApplication];
//          __block UIBackgroundTaskIdentifier taskId = [application beginBackgroundTaskWithExpirationHandler:^{
//              [application endBackgroundTask:taskId];
//              taskId = UIBackgroundTaskInvalid;
//          }];

    @weakify(self);
    // 完成下载的回调
    model.dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        SemaphoreBegin;

        @strongify(self);
        
        if (error) { ///  下载错误
            model.error = error;
            NSString *localizedDescription = [error.userInfo valueForKey:@"NSLocalizedDescription"];
            
            if ([localizedDescription isEqualToString:@"cancelled"]) {
#warning 当前任务取消了--设置啥？ 设置的正在下载！！！！！！
//                model.downloadStatus = 3;
            }else{
                model.downloadStatus = 6;
                NSLog(@"任务文件名是%@下载失败 %@",model.customCacheName,error);
                [NSNotificationCenter.defaultCenter postNotificationName:kDownloadError object:nil];
            }
            
            if (model.downloadCompletionHandler) {
                model.downloadCompletionHandler(error);
            }
        }else {
            model.downloadStatus = 4;
            model.cachePath = [YsCloudFolderManager getDownloadPathToCacheFileWithAccountCode:kAccountCode withlastPathComponent:model.lastPathComponent withName:model.customCacheName];
            NSLog(@"下载成功 -- 成功的文件的路径是%@",model.cachePath);
            /// 先删除文件，万一存在沙盒呢？
            [YsFileUtil removeItemAtPath:model.cachePath];
            /// 剪切缓存在临时目录的已下载的文件
            [YsFileUtil moveItemAtPath:model.tmpPath toPath:model.cachePath];
            if (model.downloadCompletionHandler) {
                  model.downloadCompletionHandler(nil);
              }
            [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadFinish object:nil];
            model.response = response;
            /// 自动下载
            [self checkDownload];
        }
        SemaphoreEnd;
    }];
    [model.dataTask resume];
    model.manager = manager;
}

/// 取消正在下载的任务
/// @param model 下载任务模型
- (void)cancelTask:(YsCloudFileDownloadModel *)model {
    SemaphoreBegin;
    if (model.dataTask) {
        [model.dataTask cancel];
        model.dataTask = nil;
    }
//    model.progress = 0;
    [model.manager setDataTaskDidReceiveDataBlock:NULL];
    model.response = nil;
    model.error = nil;
    [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadCancel object:nil];
    SemaphoreEnd;
}

- (void)suspendWithDownloadUrl:(NSString *)downloadUrl{
    SemaphoreBegin;
    NSParameterAssert(downloadUrl);
    YsCloudFileDownloadModel *downloadModel = [self getModelFromArray:self.downloadsArray withdownloadUrl:downloadUrl];
    /// 暂停任务
    [downloadModel.dataTask suspend];
    downloadModel.downloadStatus = 5;
    [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadSuspend object:nil];
    SemaphoreEnd;
}

- (void)suspendWithDownloadName:(NSString *)downloadName
{
    SemaphoreBegin;
    NSParameterAssert(downloadName);
    NSArray *queryNameArray = [self.downloadsArray qmui_filterWithBlock:^BOOL(YsCloudFileDownloadModel *item) {
        return [item.customCacheName isEqualToString:downloadName];
    }];
    if (queryNameArray.count == 0) return;
    YsCloudFileDownloadModel *downloadModel = [queryNameArray objectOrNilAtIndex:0];
    [downloadModel.dataTask suspend];
//    dispatch_async(dispatch_get_main_queue(), ^{
//        downloadModel.downloadStatus = 5;
//    });
    downloadModel.downloadStatus = 5;

    [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadSuspend object:nil];
    SemaphoreEnd;
}

- (void)resumeWithdownloadUrl:(NSString *)downloadUrl{
    SemaphoreBegin;
    NSParameterAssert(downloadUrl);
    YsCloudFileDownloadModel *downloadModel = [self getModelFromArray:self.downloadsArray withdownloadUrl:downloadUrl];
    downloadModel.downloadStatus = 2;
    [self checkDownload];
    [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadResume object:nil];
    SemaphoreEnd;
}

- (void)resumeWithdownloadName:(NSString *)downloadName
{
    SemaphoreBegin;
    NSParameterAssert(downloadName);
    NSArray *queryNameArray = [self.downloadsArray qmui_filterWithBlock:^BOOL(YsCloudFileDownloadModel *item) {
          return [item.customCacheName isEqualToString:downloadName];
      }];
    YsCloudFileDownloadModel *downloadModel = [queryNameArray objectOrNilAtIndex:0];
    downloadModel.downloadStatus = 2;
    [self checkDownload];
    [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadResume object:nil];
    SemaphoreEnd;
}

- (void)resumeWithdownloadModel:(YsCloudFileDownloadModel *)downloadModel
{
    SemaphoreBegin;
    NSParameterAssert(downloadModel);
    downloadModel.downloadStatus = 2;
    [self checkDownload];
    [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadResume object:nil];
    SemaphoreEnd;
}

- (void)suspendAllRequest{
    SemaphoreBegin;
    for (YsCloudFileDownloadModel *item in self.downloadsArray) {
        if (item.downloadStatus == 3 || item.downloadStatus == 2 || item.downloadStatus == 6) {
            [item.dataTask suspend];
            item.downloadStatus = 5;
        }
    }
    SemaphoreEnd;
}

- (void)resumeAllRequestBecauseofAppKill
{
    SemaphoreBegin;
    NSArray<YsCloudFileDownloadModel *> *stopDownloadModelArray = [self.downloadsArray qmui_filterWithBlock:^BOOL(YsCloudFileDownloadModel * item) {
        return item.downloadStatus == 3;
    }];
        
    [stopDownloadModelArray enumerateObjectsUsingBlock:^(YsCloudFileDownloadModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [self beginDownloadWithModel:obj];
    }];
    SemaphoreEnd;
}

#pragma mark -getterMethod
- (NSMutableArray *)downloadsArray
{
    SemaphoreBegin;
    if (!_downloadsArray) {
        _downloadsArray = [NSMutableArray array];
        /// 从realm中获取数据源
        NSArray<YsCloudFileDownloadRealmModel *> *queryDownloadArray =  [YsCloudRealmTool getDownloadTaskWithAccountCode:kAccountCode];
        for (int i = 0 ; i < queryDownloadArray.count; i++) {
            YsCloudFileDownloadRealmModel *downloadRealModel = [queryDownloadArray objectAtIndex:i];
            YsCloudFileDownloadModel *downloadModel = [[YsCloudFileDownloadModel alloc] initWithProductDownloadModel:NO];
            downloadModel.cachePath = downloadRealModel.cachePath;
            downloadModel.lastPathComponent = downloadRealModel.mime;
            downloadModel.customCacheName = downloadRealModel.customCacheName;
            downloadModel.requestUrl = downloadRealModel.requestUrl;
            downloadModel.progress = downloadRealModel.progress;
            downloadModel.requestMethod = @"Get";
            downloadModel.accountCode= downloadRealModel.accountCode;
            downloadModel.waitTaskTime = downloadRealModel.waitTaskTime;
            downloadModel.totalSize = downloadRealModel.totalSize;
            downloadModel.tmpPath = downloadRealModel.tmpPath;
            downloadModel.downloadStatus = downloadRealModel.downloadStatus;
            downloadModel.createTime = downloadRealModel.createTime;
            downloadModel.downloadReamModel = downloadRealModel;
            [_downloadsArray addObject:downloadModel];
        }
        
    }
    SemaphoreEnd;
    return _downloadsArray;
}
@end
